import { test, expect } from '@playwright/test';
import { register, generateUniqueUser } from './helpers/auth';
import {
  createArticle,
  editArticle,
  deleteArticle,
  favoriteArticle,
  unfavoriteArticle,
  generateUniqueArticle,
} from './helpers/articles';

test.describe('Articles', () => {
  test.beforeEach(async ({ page }) => {
    // Register and login before each test
    const user = generateUniqueUser();
    await register(page, user.username, user.email, user.password);
  });

  test.afterEach(async ({ context }) => {
    // Close the browser context to ensure complete isolation between tests.
    // This releases browser instances, network connections, and other resources.
    await context.close();
    // Wait 500ms to allow async cleanup operations to complete.
    // Without this delay, running 6+ tests in sequence causes flaky failures
    // due to resource exhaustion (network connections, file descriptors, etc).
    // This timing issue manifests as timeouts when loading article pages.
    // This will be investigated and fixed later.
    await new Promise(resolve => setTimeout(resolve, 500));
  });

  test('should create a new article', async ({ page }) => {
    const article = generateUniqueArticle();

    await createArticle(page, article);

    // Should be on article page
    await expect(page).toHaveURL(/\/article\/.+/);

    // Should show article content
    await expect(page.locator('h1')).toHaveText(article.title);
    await expect(page.locator('.article-content p')).toContainText(article.body);

    // Should show tags
    for (const tag of article.tags || []) {
      await expect(page.locator(`.tag-list .tag-default:has-text("${tag}")`)).toBeVisible();
    }
  });

  test('should edit an existing article', async ({ page }) => {
    const article = generateUniqueArticle();

    await createArticle(page, article);

    // Get the article slug from URL
    const url = page.url();
    const slug = url.split('/article/')[1];

    // Edit the article
    const updates = {
      title: `Updated ${article.title}`,
      description: `Updated ${article.description}`,
    };

    await editArticle(page, slug, updates);

    // Should show updated content
    await expect(page.locator('h1')).toHaveText(updates.title);
  });

  test('should delete an article', async ({ page }) => {
    const article = generateUniqueArticle();

    await createArticle(page, article);

    // Delete the article
    await deleteArticle(page);

    // Should be redirected to home
    await expect(page).toHaveURL('/');

    // Article should not appear on home page
    await expect(page.locator(`h1:has-text("${article.title}")`)).not.toBeVisible();
  });

  test('should favorite an article', async ({ page }) => {
    // Use an existing article from the demo backend (can't favorite own articles)
    await page.goto('/', { waitUntil: 'load' });

    // Click on the first article to go to its detail page
    await page.click('.article-preview h1');
    await page.waitForLoadState('load');

    // Favorite the article using the helper (which expects to be on article detail page)
    await favoriteArticle(page);

    // Should see unfavorite button (use .first() since there are 2 buttons on the page)
    await expect(page.locator('button:has-text("Unfavorite")').first()).toBeVisible();
  });

  test('should unfavorite an article', async ({ page }) => {
    // Go to home page to find an article from demo backend (not own article)
    await page.goto('/', { waitUntil: 'load' });

    // Wait for articles to load
    await page.waitForSelector('.article-preview', { timeout: 10000 });

    // Get the username of the currently logged in user from the navbar
    const currentUsername = await page.locator('nav a[href^="/profile/"]').first().textContent();

    // Find an article that's NOT from the current user
    const articles = await page.locator('.article-preview').all();
    let articleToFavorite = null;

    for (const article of articles) {
      const authorName = await article.locator('.author').textContent();
      if (authorName?.trim() !== currentUsername?.trim()) {
        articleToFavorite = article;
        break;
      }
    }

    if (!articleToFavorite) {
      throw new Error('No articles from other users found');
    }

    // Click on the article
    await articleToFavorite.locator('h1').click();
    await page.waitForURL(/\/article\/.+/);

    // Wait for article page to load - should see Favorite button (not Delete button)
    await page.waitForSelector('button:has-text("Favorite")', { timeout: 10000 });

    // Favorite it first
    await favoriteArticle(page);

    // Then unfavorite it
    await unfavoriteArticle(page);

    // Should see favorite button again (use .first() since there are 2 buttons on the page)
    await expect(page.locator('button:has-text("Favorite")').first()).toBeVisible();
  });

  test('should view article from home feed', async ({ page }) => {
    const article = generateUniqueArticle();

    await createArticle(page, article);

    // Go to home
    await page.goto('/', { waitUntil: 'load' });

    // Wait for articles to load
    await page.waitForSelector('.article-preview', { timeout: 10000 });

    // Wait for our specific article to appear
    await page.waitForSelector(`h1:has-text("${article.title}")`, { timeout: 10000 });

    // Click on the article link in the feed (h1 is inside a link)
    await Promise.all([
      page.waitForURL(/\/article\/.+/),
      page.locator(`h1:has-text("${article.title}")`).first().click(),
    ]);

    // Should be on article page
    await expect(page).toHaveURL(/\/article\/.+/);
    await expect(page.locator('h1')).toHaveText(article.title);
  });

  test('should display article preview correctly', async ({ page }) => {
    const article = generateUniqueArticle();

    await createArticle(page, article);

    // Go to home
    await page.goto('/');

    // Article preview should show correct information
    const preview = page.locator('.article-preview').first();
    await expect(preview.locator('h1')).toHaveText(article.title);
    await expect(preview.locator('p')).toContainText(article.description);

    // Should show author info
    await expect(preview.locator('.author')).toBeVisible();

    // Should show tags
    for (const tag of article.tags || []) {
      await expect(preview.locator(`.tag-list .tag-default:has-text("${tag}")`)).toBeVisible();
    }
  });

  test('should only allow author to edit/delete article', async ({ page, browser }) => {
    const article = generateUniqueArticle();

    // Create article as first user
    await createArticle(page, article);

    // Get article URL
    const articleUrl = page.url();

    // Create a second user in new context (not sharing cookies with first user)
    const context2 = await browser.newContext();
    const page2 = await context2.newPage();
    const user2 = generateUniqueUser();
    await register(page2, user2.username, user2.email, user2.password);

    // Visit the article as second user
    await page2.goto(articleUrl);

    // Should not see Edit/Delete buttons
    await expect(page2.locator('a:has-text("Edit Article")')).not.toBeVisible();
    await expect(page2.locator('button:has-text("Delete Article")')).not.toBeVisible();

    await context2.close();
  });
});
